unit ORM.Types.Base;

interface

uses
  System.SysUtils, System.Generics.Defaults, ORM.Enumerators, System.Generics.Collections;

type
  TTipo<T> = record
  strict private
    FValue: T;
    FValorReferencia: IInterface;
    function GetValue: T;
    constructor Create(const pValue: T);
  public
    property Value: T read GetValue;

    procedure Clear;
    function GetValueOrDefault: T; overload;
    function GetValueOrDefault(const pDefaultValue: T): T; overload;
    function Equals(const pOther: TTipo<T>): Boolean;
    function IsEmpty : Boolean;
    function ToString : string;

    class operator Implicit(const pValue: T): TTipo<T>;
    class operator Implicit(const pValue: TTipo<T>): T;
    class operator Equal(const pLeft, pRigth: TTipo<T>) : Boolean;
    class operator NotEqual(const pLeft, pRigth: TTipo<T>) : Boolean;
  end;

  procedure SetFlagInterface(var Intf: IInterface);

implementation

uses
  System.Rtti, ORM.Utils, ORM.Message;


function NopAddref(inst: Pointer): Integer; stdcall;
begin
  Result := -1;
end;

function NopRelease(inst: Pointer): Integer; stdcall;
begin
  Result := -1;
end;

function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
begin
  Result := E_NOINTERFACE;
end;

const
  FlagInterfaceVTable: array[0..2] of Pointer =
  (
    @NopQueryInterface,
    @NopAddref,
    @NopRelease
  );

  FlagInterfaceInstance: Pointer = @FlagInterfaceVTable;

{$REGION ' RTipo'}

constructor TTipo<T>.Create(const pValue: T);
begin
  fValue := pValue;
  SetFlagInterface(FValorReferencia);
end;


procedure TTipo<T>.Clear;
begin
  FValorReferencia := '';
  fValue := Default(T);
end;

function TTipo<T>.GetValue: T;
begin
  Result := fValue;
end;

function TTipo<T>.GetValueOrDefault: T;
begin
  Result := Default(T);
end;

function TTipo<T>.GetValueOrDefault(const pDefaultValue: T): T;
begin
  if not IsEmpty then
    Result := Value
  else
    Result := pDefaultValue;
end;

function TTipo<T>.Equals(const pOther: TTipo<T>): Boolean;
begin
  if not IsEmpty and not pOther.IsEmpty then
    Result := TEqualityComparer<T>.Default.Equals(Value, pOther.Value)
  else
    Result := IsEmpty = pOther.IsEmpty;
end;

class operator TTipo<T>.Implicit(const pValue: T): TTipo<T>;
begin
   Result := TTipo<T>.Create(pValue);
end;

function TTipo<T>.IsEmpty: Boolean;
begin
  Result := Length(FValorReferencia) = 0;
end;

class operator TTipo<T>.Implicit(const pValue: TTipo<T>): T;
begin
  Result := pValue.Value;
end;

class operator TTipo<T>.Equal(const pLeft, pRigth : TTipo<T>): Boolean;
begin
  Result := pLeft.Equals(pRigth);
end;

class operator TTipo<T>.NotEqual(const pLeft, pRigth : TTipo<T>): Boolean;
begin
  Result := not pLeft.Equals(pRigth);
end;

function TTipo<T>.ToString: string;
var
  Value : TValue;
begin
  Result := TValue.From<T>(FValue).ToString;
end;

{$ENDREGION}

end.
